//
//  DNDAppDelegate.m
//  Do Not Disturb
//
//  Created by Chris Karr on 7/19/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "DNDAppDelegate.h"
#import "ObserverManager.h"
#import "Observer.h"
#import "NaiveBayesLearner.h"
#import "DNDDefines.h"

@implementation DNDAppDelegate

- (DNDAppDelegate *) init
{
	if (self = [super init])
	{
		sensors = [ObserverManager observers];
		trainingTimer = nil;
		timer = nil;
		
		logger = [[LearnerLogger alloc] init];
		NaiveBayesLearner * l = [[NaiveBayesLearner alloc] init];
		[logger setLearner:l];
	}
	
	return self;
}

- (void) activateStatusMenu
{
    NSStatusBar *bar = [NSStatusBar systemStatusBar];
 
    theItem = [bar statusItemWithLength:NSVariableStatusItemLength];
    [theItem retain];
 
    [theItem setTitle:nil];
    [theItem setImage:[NSImage imageNamed:@"bell-small"]];
    [theItem setAlternateImage:[NSImage imageNamed:@"bell-small-alt"]];
    [theItem setHighlightMode:YES];
    [theItem setMenu:menu];
	
	available = YES;
}

- (void) awakeFromNib
{
	[self activateStatusMenu];
	
	[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUpdate:) name:DND_UPDATE 
		object:nil];

	[eventsWindow setTitle:@"Do Not Disturb - Collecting Information"];
	[eventsWindow setBackgroundColor:[NSColor colorWithCalibratedWhite:0.8 alpha:1.0]];
	
	NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];

	float interval = [defaults floatForKey:@"Sensor Interval"];
	
	if (interval == 0.0)
	{
		interval = 30.0;
		
		[defaults setFloat:interval forKey:@"Sensor Interval"];
	}

	[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"Sensor Interval" options:NSKeyValueObservingOptionNew context:NULL];
	[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"Training Interval" options:NSKeyValueObservingOptionNew context:NULL];
	[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"Contexts" options:NSKeyValueObservingOptionNew context:NULL];
	
	timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(scanAgain:) userInfo:nil repeats:YES];
	progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES];

	[updateProgress setMaxValue:(double) interval];
	[updateProgress setMinValue:0.0];
	[updateProgress setDoubleValue:0.0];
	[updateProgress setUsesThreadedAnimation:YES];
	
	[self scan:self];
}

- (void) observeValueForKeyPath: (NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
	NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];

	if ([keyPath isEqual:@"Sensor Interval"])
	{
		float interval = [defaults floatForKey:@"Sensor Interval"];

		if (interval > 0.0)
		{
			[timer invalidate];
			[progressTimer invalidate];
			
			timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(scanAgain:) userInfo:nil repeats:YES];
			progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES];

			[updateProgress setMaxValue:(double) interval];
			[updateProgress setDoubleValue:0.0];
		}
	}
	else if ([keyPath isEqual:@"Training Interval"])
	{
		float interval = [defaults floatForKey:@"Training Interval"];

		if (interval > 0.0 && trainingTimer != nil)
		{
			[trainingTimer invalidate];

			trainingTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(trainAgain:) userInfo:nil repeats:YES];
			[trainingTimer retain];
		}
	}
	else if ([keyPath isEqual:@"Contexts"])
	{

	}
}

- (void) scanAgain:(NSTimer *) t
{
	[self scan:t];
	
	[updateProgress setDoubleValue:0.0];
}

- (void) updateProgress:(NSTimer *) t
{
	[updateProgress incrementBy:1.0];
}

- (IBAction) about:(id) sender
{
	[NSApp orderFrontStandardAboutPanel:sender];
}

- (IBAction) preferences:(id) sender
{
	if ([preferencesWindow isVisible])
		[preferencesWindow orderOut:sender];
	else
	{
		[NSApp activateIgnoringOtherApps:YES];
		[preferencesWindow makeKeyAndOrderFront:sender];
	}
}

- (IBAction) quit:(id) sender
{
	[NSApp terminate:sender];
}

- (IBAction) scan:(id) sender
{
	Observer * sensor;
	NSEnumerator * iter = [sensors objectEnumerator];

	while ((sensor = (Observer *) [iter nextObject]))
	{
		if ([sensor isEnabled])
			[sensor scan];
	}
}

- (IBAction) toggleScan:(id) sender
{
	if (timer == nil)
	{
		NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
		float interval = [defaults floatForKey:@"Sensor Interval"];
		
		if (interval == 0.0)
			interval = 60.0;

		timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(scanAgain:) userInfo:nil repeats:YES];
		progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES];

		[updateProgress setUsesThreadedAnimation:YES];

		[updateProgress setMaxValue:(double) interval];
		[updateProgress setMinValue:0.0];

		[updateProgress setDoubleValue:0.0];

		[pause setTitle:@"Pause"];
		[eventsWindow setTitle:@"Do Not Disturb - Collecting Information"];
	}
	else
	{
		[timer invalidate];
		timer = nil;
		
		[pause setTitle:@"Resume"];
		[eventsWindow setTitle:@"Do Not Disturb - Paused"];
	}
}

- (IBAction) toggleEventLog:(id) sender
{
	if ([eventsWindow isVisible])
		[eventsWindow orderOut:sender];
	else
	{
		[NSApp activateIgnoringOtherApps:YES];
		[eventsWindow makeKeyAndOrderFront:sender];
	}
}

- (IBAction) togglePredictedStatus:(id) sender
{
	if ([predictionWindow isVisible])
		[predictionWindow orderOut:sender];
	else
	{
		[NSApp activateIgnoringOtherApps:YES];
		[predictionWindow makeKeyAndOrderFront:sender];
	}
}

- (IBAction) clear:(id) sender
{
	[eventsController setFilterPredicate:nil];
	[eventsController removeObjects:[eventsController arrangedObjects]];
}

- (NSString *) getTrainingStatus
{
	if (trainingTimer == nil)
		return @"Not Training";
	else
		return @"Training";
}

- (NSNumber *) getExampleCount
{
	return [logger readingCount];
}

- (NSSet *) getSensors
{
	return sensors;
}

- (void) setSensors:(NSSet *) sensors
{

}

- (IBAction) toggleTraining:(id) sender
{
	[self willChangeValueForKey:@"trainingStatus"];

	if (trainingTimer == nil)
	{
		NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
		float interval = [defaults floatForKey:@"Training Interval"];
		
		if (interval == 0.0)
			interval = 60.0;

		trainingTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(trainAgain:) userInfo:nil repeats:YES];
		[trainingTimer retain];
		[trainingButton setTitle:@"Stop"];
		[trainingItem setTitle:@"Stop Training..."];

		NSRunInformationalAlertPanel (@"Training started", @"Training has been started. The learner will periodically prompted you for the current context. ", @"OK", nil, nil);
	}
	else
	{
		[trainingTimer invalidate];
		
		trainingTimer = nil;
		[trainingButton setTitle:@"Start"];
		[trainingItem setTitle:@"Start Training..."];
		
		NSRunInformationalAlertPanel (@"Training Stopped", @"Training has been stopped.", @"OK", nil, nil);
	}

	[self didChangeValueForKey:@"trainingStatus"];
}

- (void) trainAgain:(NSTimer *) t
{
	[self scan:self];
	
	if ([[NSUserDefaults standardUserDefaults] boolForKey:@"Prompt Sound"])
		[[NSSound soundNamed:@"bell"] play];
	
	[theItem setImage:[NSImage imageNamed:@"bell-small-color"]];
	
	[NSApp activateIgnoringOtherApps:YES];
	[trainingWindow makeKeyAndOrderFront:self];
}

- (IBAction) setStatus:(id) sender
{
	[self trainAgain:nil];
}

- (IBAction) setTrainingContext:(id) sender
{
	[self willChangeValueForKey:@"predictedStatus"];
	[self willChangeValueForKey:@"exampleCount"];
	[theItem setImage:[NSImage imageNamed:@"bell-small"]];

	[trainingWindow orderOut:self];

	NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];

	float interval = [defaults floatForKey:@"Sensor Interval"];
		
	if (interval == 0.0)
		interval = 60.0;

	NSString * label = [statePulldown stringValue];
	
	[defaults setValue:label forKey:@"Last Context"];
	
	NSMutableArray * contexts = [NSMutableArray arrayWithArray:[defaults valueForKey:@"Contexts"]];
	if (![contexts containsObject:label])
	{
		[contexts addObject:label];
		[contexts sortUsingSelector:@selector(compare:)];
		
		[defaults setValue:contexts forKey:@"Contexts"];
	}
	
	NSMutableArray * readings = [NSMutableArray array];

	NSArray * events = [eventsController arrangedObjects];
	
	NSEnumerator * iter = [events objectEnumerator];
	NSDictionary * event;
	
	NSDate * now = [NSDate date];
	
	while (event = [iter nextObject])
	{
		NSDate * date = [event valueForKey:@"date"];

		if ([now timeIntervalSinceDate:date] <= interval)
			[readings addObject:event];
	}

	[logger logLabel:label readings:readings];

	[self didChangeValueForKey:@"exampleCount"];
	[self didChangeValueForKey:@"predictedStatus"];
	
	[privacyManager captureScreen:sender];
}

- (NSString *) getPredictedStatus
{
	float interval = [[NSUserDefaults standardUserDefaults] floatForKey:@"Sensor Interval"];
	
	if (interval == 0.0)
		interval = 60.0;

	NSArray * events = [eventsController arrangedObjects];
	
	NSMutableArray * activeEvents = [NSMutableArray array];
		
	NSEnumerator * iter = [events objectEnumerator];
	NSDictionary * event;
	
	NSDate * now = [NSDate date];
	
	while (event = [iter nextObject])
	{
		NSDate * date = [event valueForKey:@"date"];

		if ([now timeIntervalSinceDate:date] <= interval)
			[activeEvents addObject:event];
	}

	Learner * l = [logger getLearner];
		
	return [l getLabelForExample:activeEvents];
}

- (void) handleUpdate:(NSNotification *) msg
{
	[self willChangeValueForKey:@"predictedStatus"];

	[eventsController addObject:[msg userInfo]];

	[self didChangeValueForKey:@"predictedStatus"];

	[[NSDistributedNotificationCenter defaultCenter] postNotificationName:DND_PREDICTION_UPDATE object:nil userInfo:nil];
}

- (IBAction) clearLog:(id) sender
{
	[self willChangeValueForKey:@"exampleCount"];

	[logger clear];

	[self didChangeValueForKey:@"exampleCount"];
}

@end
